﻿using IGeekFan.AspNetCore.Knife4jUI;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using NetRpc.Http;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;
using System.Runtime.CompilerServices;
using TK.Common.Swagger;

namespace Microsoft.Extensions.DependencyInjection
{
    /// <summary>
    /// swagger扩展
    /// </summary>
    public static class SwaggerExtension
    {
        /// <summary>
        /// 扩展swagger服务,默认查找应用程序根目录所有xml文件
        /// </summary>
        public static IServiceCollection AddTKSwagger(this IServiceCollection services, Action<SwaggerGenOptions> action = null, string[] xmlPath = null)
        {
            services.AddSwaggerGen(option =>
            {
                action?.Invoke(option);
                option.CustomOperationIds(apiDesc => {
                    var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
                    return controllerAction.ControllerName + "-" + controllerAction.ActionName;
                    });
                option.CustomSchemaIds(t => t.ToString());
                option.IgnoreObsoleteActions();
                option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, Name = "Authorization" });
                option.AddSecurityRequirement(new OpenApiSecurityRequirement());
                option.SchemaFilter<EnumSingleSchemaFilter>();
                //option.SchemaFilter<EnumSchemeFilter>();
                //option.DocumentFilter<EnumDocumentFilter>();
                if (xmlPath == null || xmlPath.Length== 0)
                {
                    xmlPath = Directory.GetFiles(AppContext.BaseDirectory, "*.xml",SearchOption.TopDirectoryOnly);
                    if (xmlPath.Length>0 )
                        foreach (var path in xmlPath)
                            option.IncludeXmlComments(path, true);
                }
            });

            return services;
        }

        /// <summary>
        /// 扩展swagger服务
        /// </summary>
        /// <param name="app">IApplicationBuilder</param>
        /// <param name="routeTemplate">swagger文件路由模板,默认apidoc/{documentName}/swagger.{json|yaml}; 'documentName'须与swagger服务里的文档名称对应，默认v1</param>
        /// <param name="action">swagger ui配置；RoutePrefix和SwaggerEndpoint须与路由模板匹配</param>
        /// <returns></returns>
        public static IApplicationBuilder UseTKSwagger(this IApplicationBuilder app,
            string routeTemplate = "apidoc/{documentName}/swagger.{json|yaml}",
            Action<Knife4UIOptions> action = null)
        {
            app.FixNoHttpMethodAction();
            using(var scope = app.ApplicationServices.CreateScope())
            {
                var genOption = scope.ServiceProvider.GetService<IOptions<SwaggerGeneratorOptions>>();
                var dic = genOption.Value.SwaggerDocs;
            }
            app.UseSwagger(option =>
            {
                option.RouteTemplate = "apidoc/{documentName}/swagger.{json|yaml}";
            });
            app.UseKnife4UI(uiOption =>
            {
                if (action != null)
                {
                    action(uiOption);
                }
                else
                {
                    uiOption.RoutePrefix = "apidoc";
                    uiOption.SwaggerEndpoint("v1/swagger.json", "API Docs");
                }
            });
            return app;
        }

        /// <summary>
        /// 修复无httpmethod action
        /// </summary>
        public static void FixNoHttpMethodAction(this IApplicationBuilder app)
        {
            var apiGroup = app.ApplicationServices.GetService<IApiDescriptionGroupCollectionProvider>();
            if (apiGroup != null)
                foreach (var group in apiGroup.ApiDescriptionGroups.Items)
                    foreach (var item in group.Items)
                    {
                        if (string.IsNullOrWhiteSpace(item.HttpMethod))
                            item.HttpMethod = "GET";
                    }
        }
    }
}
